Be more defensive in the parser translator lexer#3551
Conversation
|
Hi @kddnewton, sorry for the bother but can you check this out? |
|
|
||
| if percent_array?(quote_stack.pop) | ||
| prev_token = lexed[index - 2][0] if index - 2 >= 0 | ||
| prev_token, _ = lexed[index - 2] |
There was a problem hiding this comment.
This is going to wrap around now, but I don't think it should
There was a problem hiding this comment.
Oops, indeed. I should not have removed that
|
|
||
| prev_token = lexed[index - 2][0] if index - 2 >= 0 | ||
| next_token = lexed[index][0] | ||
| prev_token, _ = lexed[index - 2] |
There was a problem hiding this comment.
Same here, we don't want it to wrap
329bd6e to
b1a9b32
Compare
| current_length += token.value.bytesize | ||
| # Heredoc interpolation can have multiple STRING_CONTENT nodes on the same line. | ||
| is_first_token_on_line = lexed[index - 1] && token.location.start_line != lexed[index - 2][0].location&.start_line | ||
| is_first_token_on_line = lexed[index - 1] && token.location.start_line != lexed[index - 2]&.first.location&.start_line |
There was a problem hiding this comment.
Is it possible for lexed[index - 2] to be nil here? If it is, then we need &.location as well. If it's not, then we shouldn't use &.first
There was a problem hiding this comment.
I meant this to be "safe" safe navigation. I don't believe this matters for valid syntax, but with invalid one I can't say so wanted to be on the safe side.
b1a9b32 to
63e30a1
Compare
|
Any chance to get this merged? This is also a problem for rubocop extensions that try to extract ruby code from templating like erb or slim (r7kamura/rubocop-slim#31) |
|
|
||
| while !((next_token = lexed[index][0]) && next_token.type == :EMBDOC_END) && (index < length - 1) |
There was a problem hiding this comment.
I think you can also do the same line 284?
There was a problem hiding this comment.
Yeah, that works (if you meant what I changed that is)
| current_length += token.value.bytesize | ||
| # Heredoc interpolation can have multiple STRING_CONTENT nodes on the same line. | ||
| is_first_token_on_line = lexed[index - 1] && token.location.start_line != lexed[index - 2][0].location&.start_line | ||
| is_first_token_on_line = lexed[index - 1] && token.location.start_line != lexed[index - 2]&.first&.location&.start_line |
There was a problem hiding this comment.
Can we avoid the mix of index accesses and first with something like this?
| is_first_token_on_line = lexed[index - 1] && token.location.start_line != lexed[index - 2]&.first&.location&.start_line | |
| prev_prev_token, _ = lexed[index - 2] if index - 2 >= 0 | |
| is_first_token_on_line = lexed[index - 1] && token.location.start_line != prev_prev_token&.location&.start_line |
There was a problem hiding this comment.
Yeah, sure. It's a bit better. It's actually just prev_token, even if it is[index -2]. Right at the top of the loop index already gets incremented so you need to unintuitively look back a bit further.
I should move most of the state from the huge to_a into the class itself to make writing helper methods more convenient sometime.
247e841 to
a932a4f
Compare
| result = Float::MAX | ||
|
|
||
| while (lexed[next_token_index] && next_token = lexed[next_token_index][0]) | ||
| while (next_token, _ = lexed[next_token_index]) |
There was a problem hiding this comment.
I don't think the behaviour of these two constructs (old and new) will be the same in every instance. For example:
irb> foo = [nil, 1]
#=> [nil, 1]
irb> while (i, _ = foo); puts "42"; break; end
42
#=> nil
irb> while (i = foo&.first); puts "42"; break; end
#=> nilThe same would be true for any assignments in if conditions as well.
I would very much like to see &.first instead of destructuring used to safely get these values, since its behaviour would be the same as [0] (but safe against nil values) and I also find that it is more readable.
There was a problem hiding this comment.
Good catch, I was expecting the destructure to be falsy
There was a problem hiding this comment.
The token being nil would be a bug in prism I believe (and probably blow up in a different place later). I can see now how this isn't quite the same but practially the difference should be zero.
Anyways, I changed it.
There was a problem hiding this comment.
Thanks for changing it, but I don't get why you think it would be a bug. The loop is explicitly conditional on the next_token being truthy, and if it isn't it should break.
There was a problem hiding this comment.
I was just saying that this difference shouldn't matter for the data that prism provides. It's always [token, some_internal_state], if there's no token (nil, then that should not have been part of lexed in the first place.
Generally I have been good about safely accessing the tokens but failed to properly guard against no tokens in places where it could theoretically happen through invalid syntax. I added a test case for one occurance, other changes are theoretical only.
a932a4f to
4a3866a
Compare
|
Thanks everyone |
|
Thanks for your patience @Earlopain — I'll be much faster when I'm back from paternity leave. |
|
@kddnewton don't worry about it at all. Your labour on the previous PRs more than makes up for it |
Fixes rubocop/rubocop#14100
Fixes #3550
Generally I have been good about safely accessing the tokens but failed to properly guard against no tokens in places
where it could theoretically happen through invalid syntax.
I added a test case for one occurance, other changes are theoretical only.
Also, TIL that this works:
I make use of that construct to safely access the data without much changes. Makes some code easier actually.